#pragma once
#include "Sock.h"
#include "snetwork/NluHttpRequest.h" 

#define     CRLF                "\x0d\x0a"
#define     CR      13          //huiche     /r
#define     LF      10          //huanhang   /n
#define     HTTP_BREAK      9001
#define     HTTP_CONTINUE   9002

#define http_hash(key, c)   ((unsigned int) key * 31 + c)

#define NL_HTTP_str3_cmp(m, c0, c1, c2, c3)                                       \
    m[0] == c0 && m[1] == c1 && m[2] == c2

#define NL_HTTP_str3Ocmp(m, c0, c1, c2, c3)                                       \
    m[0] == c0 && m[2] == c2 && m[3] == c3

#define NL_HTTP_str4cmp(m, c0, c1, c2, c3)                                        \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3

#define NL_HTTP_str5cmp(m, c0, c1, c2, c3, c4)                                    \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4

#define NL_HTTP_str6cmp(m, c0, c1, c2, c3, c4, c5)                                \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
        && m[4] == c4 && m[5] == c5

#define NL_HTTP_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                       \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
        && m[4] == c4 && m[5] == c5 && m[6] == c6

#define NL_HTTP_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7)                        \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
        && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7

#define NL_HTTP_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8)                    \
    m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3                      \
        && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8


static int  usual[] = {
    0xffffdbfe, /* 1111 1111 1111 1111  1101 1011 1111 1110 */

                /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
    0x7fff37d6, /* 0111 1111 1111 1111  0011 0111 1101 0110 */

                /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
#if (NGX_WIN32)
    0xefffffff, /* 1110 1111 1111 1111  1111 1111 1111 1111 */
#else
    0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
#endif

                /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
    0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

    0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
    0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
    0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
    0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
};

class  SNETWORK_API Sock::CNluHttpParse
{
public:
    static CNluHttpParse *instance(void*);
    int ParseRequestLine(nl_http_request_t *rr, http_buf_t *b);
    int ParseHeaderLine(http_buf_t *b, nl_http_request_t *r, unsigned int allow_underscores);                  
    int ParseSwStart();          
    int ParseSwMethod(char *m);
    int ParseSwSpacesBeforeUri();
    int ParseSwSchema();
    int ParseSwSchemaSlash();
    int ParseSwSchemaSlashSlash();
    int ParseSwHost();
    int ParseSwPort();  
    int ParseSwHostHttp09();    
    int ParseSwAfterSlashInUrl();                
    int ParseSwCheckUri(); 
    int ParseSwCheckUriHttp09();                                        
    int ParseSwUri();           
    int ParseSwHttp09();            
    int ParseSwHttpH();            
    int ParseSwHttpHT();            
    int ParseSwHttpHTT();            
    int ParseSwHttpHTTP();            
    int ParseSwFirstMajorDigit();            
    int ParseSwMajorDigit();
    int ParseSwFirstMinorDigit();            
    int ParseSwMinorDigit();
    int ParseSwSpacesAfterDigit();            
    int ParseSwAlmostDone();
    CNluHttpParse();
    
protected:
	int m_sockfd;
	nl_http_request_t *m_r;
	char *m_p;
	enum {
        sw_start = 0,
        sw_method,
        sw_spaces_before_uri,
        sw_schema,
        sw_schema_slash,
        sw_schema_slash_slash,
        sw_host,
        sw_port,
        sw_host_http_09,
        sw_after_slash_in_uri,
        sw_check_uri,
        sw_check_uri_http_09,
        sw_uri,
        sw_http_09,
        sw_http_H,
        sw_http_HT,
        sw_http_HTT,
        sw_http_HTTP,
        sw_first_major_digit,
        sw_major_digit,
        sw_first_minor_digit,
        sw_minor_digit,
        sw_spaces_after_digit,
        sw_almost_done
    } m_state;
	
private: 
    static CNluHttpParse* m_instance;
    class CGarbo {public: ~CGarbo(){if (CNluHttpParse::m_instance) delete CNluHttpParse::m_instance;}};
    static CGarbo Garbo;	
};
